home *** CD-ROM | disk | FTP | other *** search
/ Games of Daze / Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso / x2ftp / msdos / pmode / 386p_099 / 386power.asm < prev    next >
Encoding:
Assembly Source File  |  1994-05-03  |  75.4 KB  |  2,202 lines

  1. ; 386POWER v1.00 is part of the public domain portion 
  2. ; of the  XGE system
  3. ; XGE == eXtended Game Engine 
  4. ;  see 386power.doc for more info & credits
  5.           
  6.         .386p
  7.         
  8. ; Use int 33h to call a v86 interrupt routine from protected mode
  9. ; Use int 32h to call a 32bit     procedure (16bit to 32bit & back)
  10. ; Use int 32h to call a 16bit v86 procedure (32bit to 16bit & back)
  11.  
  12. ; respect this segment order or you'll get troubles
  13. code16  segment para public use16
  14. code16  ends
  15. code32  segment para public use32
  16. code32  ends
  17. codeend segment para stack use32 'stack'
  18. codeend ends
  19.  
  20.         include 386power.inc
  21.         
  22. ;=======================================
  23. ; Real mode and 16bit 386 code
  24. ;=======================================
  25. code16  segment para public use16
  26.         assume cs:code16, ds:code16
  27.         org 0
  28.         align byte
  29.         
  30. ; this macro is used to produce debug messages under real mode
  31. say     macro  t_item
  32.         push dx
  33.         push ax
  34.         mov dx, offset t_item
  35.         mov ah,09
  36.         int 21h
  37.         pop ax
  38.         pop dx
  39.         endm
  40.         
  41. Test386 macro 
  42.         ; Detect if current processor is a 386
  43.         pushf ; save flags
  44.         xor ah,ah ; pseudo_flags tutti azzerati
  45.         push ax  ;
  46.         popf     ;  flags tutte azzerate
  47.         pushf    ; 
  48.         pop ax   ;  recupera flags 
  49.         and ah,0f0h ; elimina CARRY,PARITY
  50.         cmp ah,0f0h ; 
  51.         jz NotA386  ; ci sono flag superiori, il 386 non li maschera
  52.         mov ah,0f0h ; riprova con i bit4..bit7 posti ad 1
  53.         push ax ;
  54.         popf    ; analogo
  55.         pushf   ; 
  56.         pop ax  ; idem
  57.         popf    ; reload flags
  58.         and ah,0f0h ;
  59.         jnz Is386   ; alcuni flags ci sono, il 386 non li maschera
  60. NotA386:
  61.         mov dx,offset em0_no386
  62.         jmp exit16err
  63. Is386:        
  64.         endm
  65.  
  66. DOSRAMTOP = 0002
  67.  
  68. Boot16: ; DOS EXTENDER starts here and kicks program into 386 protected mode
  69.         mov ax,cs
  70.         mov ds,ax
  71.         mov ax,0003 ; set 80x25 text mode
  72.         int 10h     ;
  73.         
  74.         ; show who holds the copyrights etc. etc.
  75.         mov dx,offset _386power_info
  76.         mov ah,09
  77.         int 21h        
  78.         
  79.         Test386   
  80.         say msg_386
  81.  
  82.         pushf
  83.         pop ax
  84.         mov ds:V86F,ax
  85.         say msg_gints
  86.         ; copy old ints before kicking into the prot. mode
  87.         mov si,offset _OldInt
  88.         mov ax,03500h ; get interrupt vectors
  89.         push es
  90. getints:
  91.         int 21h
  92.         mov [si],bx
  93.         add si,2
  94.         mov [si],es
  95.         add si,2
  96.         inc al
  97.         jnz getints
  98.         pop es
  99.         
  100.         ; install int 32h handler for 
  101.         ; real_mode TO protected_mode calls
  102.         ; (available only from the real mode side of 386Powered programs)
  103.         ; WARNING! This real->prot mode proc call doesn't pass virtual
  104.         ; register values.
  105.         mov  ax,02532h
  106.         mov  dx,offset REAL_VCPI_DPMI_INT32      
  107.         ; ds:dx == ptr to new int handler
  108.         int 21h
  109.         say msg_typeslow
  110.         ; Now set typematic rate to the lowest values
  111.         mov ax,0305h ; typematic_rate set_rate
  112.         mov bx,001Fh ; 00 == 250msec delay_value  1F == 2char/sec repeat_rate
  113.         int 16h
  114.         
  115.         cli ; turn off interrupts while initializing
  116.         cld ; The only way is UP! (er.. the default is up)
  117.         
  118.         ; Now it's time to convert pointers from
  119.         ; seg:ofs to LINEAR or EXTENDED
  120.         
  121.         mov    ax,es        ; PSP LINEAR OFFSET      
  122.         movzx eax,ax        ;       
  123.         shl eax,4           ; 
  124.         mov ds:_PSPBase,eax ;
  125.         
  126.         mov eax,code16         ; CODE16 LINEAR ADDRESS
  127.         shl eax,4              ;
  128.         mov ds:_Code16Base,eax ;
  129.         
  130.     mov ebx,code32         ; CODE32 LINEAR ADDRESS
  131.         shl ebx,4              ;
  132.         mov ds:_Code32Base,ebx ;
  133.         
  134.         or dword ptr ds:GDTcode16[2],eax ; SET UP code16 and data16 GTD entries
  135.         or dword ptr ds:GDTdata16[2],eax ;
  136.         
  137.         or dword ptr ds:GDTcode32[2],ebx ; SET UP code32 and data32 GTD entries
  138.         or dword ptr ds:GDTdata32[2],ebx ;
  139.         
  140.         add dword ptr ds:s16_GDTaddr[2],ebx ; SET UP GTD descriptor
  141.         
  142.         mov eax,codeend               ; ebx == code32  linear address
  143.         shl eax,4                     ; eax == codeend linear address
  144.         sub eax,ebx                   ; eax == codeend offset from code32
  145.         mov ds:_LoMemBase,eax         ; set lomembase ( it grows up   )
  146.         mov ds:StackBaseAddress,eax   ; set stackbase ( it grows down )
  147.         
  148.         movzx eax,word ptr es:[DOSRAMTOP] ; get low memory size in paragraphs
  149.         shl eax,4                 ; para to bytes
  150.         sub eax,ebx               ; code32 relative offset
  151.         mov ds:_LoMemTop,eax      ; set low memory top
  152.         mov dx,offset em1_no_lomem
  153.         cmp eax,00
  154.         jg  ramright
  155.         jmp exit16err
  156. ramright:        
  157.     mov eax,STACKSIZE*16  ; set up stack frame
  158.         call InitAlloc        ;
  159.  
  160.         push es ; save PSP seg (DPMI test may kill ES)
  161.     pop fs  ;
  162.         
  163.         say msg_DPMItest
  164.         ; now TEST FOR DPMI
  165.     mov ax,1687h   ; Get Real-to-Protected-Mode Switch entry point:
  166.                ;
  167.                ; The entry point you get must be called ONLY ONCE
  168.                ; FOR THE FIRST SWITCH to DPMI protected mode.
  169.                ; Input:
  170.                ;    AX = 1687h
  171.                ; Output:
  172.                ;    AX = 0 if function successfull
  173.                ;        BX = DPMI flags
  174.                        ;             bit 0:    0 = 16bit program support only
  175.                        ;                       1 = 32bit program support
  176.                ;             bit 1..15 NOT USED
  177.                ;        CL = processor type 02h= 80286
  178.                ;                    03h= 80386
  179.                ;                            04h= 80486
  180.                ;                            05h= Pentium ?
  181.                ;                            06h..0FFh = not used
  182.                ;        DH = DPMI version major number (binary)
  183.                ;        DL = DPMI version minor number (binary)
  184.                ;           [386power fully supports DPMI 0.9 and 1.0]
  185.                ;        SI = number of paragraphs required for
  186.                ;         DPMI host private data (it may be 0)
  187.                ;        ES:DI = segment:offset of procedure to call
  188.                ;                to enter protected mode
  189.  
  190.     int 2fh        ;
  191.     or ax,ax       ;
  192.     jz StartDPMI   ; Go DPMI if present
  193.         
  194.         say msg_VCPItest
  195.         ; Not DPMI, try VCPI, this is a lot more complex
  196.         mov eax,0
  197.         mov gs,ax
  198.         cmp eax, gs:(4*67h) ; NULL vector ?
  199.         je short NotIntoVCPI
  200.         mov ax,0de00h       ;
  201.         int 67h             ;  Call VCPI INSTALLATION CHECK
  202.         or ah,ah            ;
  203.         jnz short NotIntoVCPI   ; if (ah != 0) it isn't VCPI
  204.         jmp StartVCPI
  205. NotIntoVCPI:
  206.  
  207.         ; No other VMM is supported
  208.         mov dx,offset emN_VMM
  209.         jmp exit16err
  210.         
  211. ; teletyper calls the dos function int 21h, ah=09
  212. ; under DPMI once the GS segment is set up (l
  213.  
  214. teletyper:
  215.         ; DPMI teletyper
  216.         pushad
  217.         push es
  218.         mov es,ds:_EXIT_DATA_SEL
  219.         mov ds:V86ds,code16
  220.         mov ds:V86edx,edx
  221.         mov ds:V86ah,9
  222.         mov bx,0021h
  223.         mov cx,0
  224.         mov edi, offset ds:V86edi
  225.         mov ax,300h
  226.         int 31h
  227.         pop es
  228.         popad
  229.         ret
  230.         
  231. psay macro d_item
  232.         push edx
  233.         mov  edx, offset code16:d_item
  234.         call teletyper
  235.         pop edx
  236.         endm
  237.  
  238. ;------------------------------------------------------------------------------
  239. ; 16 bit common system data
  240.  
  241. CR = 0dh
  242. LF = 0ah
  243.  
  244. ; debug messages
  245. msg_386      db ' Found 386 CPU or higher',CR,LF,'$'
  246. msg_DPMItest db ' Checking DPMI',CR,LF,'$'
  247. msg_VCPItest db ' Checking VCPI',CR,LF,'$'
  248. msg_typeslow db ' Slowing down typematic rate',CR,LF,'$'
  249. msg_type     db ' Setting default typematic rate',CR,LF,'$'
  250. msg_gints    db ' Saving DOS interrupt table',CR,LF,'$'
  251. msg_rints    db ' Restoring DOS interrupt table',CR,LF,'$'
  252. msg_end      db ' Terminating program ... CIAO! See you later.',CR,LF,'$'
  253. msg_DPMImem  db ' Calling DPMI function 501h to allocate extended memory'
  254.              db   CR,LF,'$'
  255. msg_DPMIwin  db ' Extended memory allocated',CR,LF,'$'
  256. msg_DPMIirq  db ' Setting new DPMI irq handlers',CR,LF,'$'
  257. msg_VCPIfree db ' Freeing pages allocated thru VCPI',CR,LF,'$'
  258.  
  259. emN_VMM db ' 386Power found no VCPI or DPMI manager installed',CR,LF
  260.         db ' Check if you have at least a 386 Extended Memory Manager',CR,LF
  261.         db ' properly configurated and then try again',CR,LF
  262.         db ' this program should run fine with EMM386, QEMM, 386MAX ',CR,LF
  263.         db ' or Microsoft Windows running in 386 enhanced mode',CR,LF,'$'
  264.  
  265. ; hex ->ascii translation table
  266. emT_hextable db '0123456789ABCDEF'
  267.  
  268. ; standard message             
  269. emX_stderr   db '[ See file 386ERROR.TXT for more info ]',7,CR,LF,'$'
  270.  
  271. ; error strings
  272. em0_no386    db 'Error 00: 386 COMPATIBLE PROCESSOR NOT DETECTED!',CR,LF,'$'
  273. em1_no_lomem db 'Error 01: NOT ENOUGH MEMORY UNDER 640KB!',CR,LF,'$'
  274. em2_unkV86   db 'Error 02: UNKNOWN MEMORY MANAGER DRIVES V86 MODE!',CR,LF,'$'
  275. em3_no_himem db 'Error 03: NOT ENOUGHT MEMORY ABOVE 1MB!',CR,LF,'$'
  276. em4_noA20    db 'Error 04: A20 ADDRESS LINE NOT ENABLED!',CR,LF,'$'
  277. em5_hifault  db 'Error 05: FAILED ALLOCATION OF MEMORY ABOVE 1MB!',CR,LF,'$'
  278. em6_PICfault db 'Error 06: VCPI P.I.C. INT MAPPED ON 386POWER INTS',CR,LF,'$'
  279. em7_noDPMI32 db 'Error 07: NOT A 32 BIT DPMI HOST!',CR,LF,'$'
  280. em8_DPMIdesc db 'Error 08: NOT ENOUGH DPMI DESCRIPTORS!',CR,LF,'$'
  281. em9_DPMImod  db 'Error 09: CANNOT MODIFY DPMI DESCRIPTORS!',CR,LF,'$'
  282. emA_FIX      db 'Error 0A: VCPI HAS NOT ENOUGH PAGES AVAILABLE!',CR,LF,'$'
  283. emB_lowDPMI  db 'Error 0B: DPMI API IS OLDER THAN DPMI 0.9',CR,LF,'$'
  284. emC_linear   db 'Error 0C: LINEAR MEMORY SPACE EXAUSTED',CR,LF,'$'
  285. emD_phys     db 'Error 0D: PHISYCAL MEMORY SPACE EXAUSTED',CR,LF,'$'
  286. emE_backing  db 'Error 0E: BACKING STORAGE EXAUSTED',CR,LF,'$'
  287. emF_handle   db 'Error 0F: INVALID HANDLE',CR,LF,'$'
  288. em10_invalid db 'Error 10: INVALID PARAMETER VALUE',CR,LF,'$'
  289. em11_EqPIC   db 'Error 11: P.I.C. MAP ON SAME INTERRUPT SLOT',CR,LF,'$'
  290.  
  291. _386power_info db CR,LF
  292.   db '┌────────────────────────────────────────────────────────────┐',CR,LF
  293.   db '│  386Power Dos-Extender     386P Revision 0.999 BETA        │',CR,LF
  294.   db '│                                                            │',CR,LF
  295.   db '│     This is a public domain dos-extender module            │',CR,LF  
  296.   db '│     designed for a VCPI/DPMI interface to protected mode.  │',CR,LF  
  297.   db '│     You need a VCPI or DPMI manager to run this.           │',CR,LF
  298.   db '│                                                            │',CR,LF    
  299.   db '│     (c) Copyright Lorenzo Micheletto MCHLNZ67T19C890A      │',CR,LF
  300.   db '│     All rights reserved, except the portions of 386Power   │',CR,LF
  301.   db '│     based on the source code of the PMODE dos-extender     │',CR,LF  
  302.   db '│     by Thomas "Tran" Pytel.                                │',CR,LF  
  303.   db '│     See the 386Power documentation for explanations.       │',CR,LF  
  304.   db '│                                                            │',CR,LF      
  305.   db '└────────────────────────────────────────────────────────────┘',CR,LF  
  306.   db CR,LF,'$' 
  307.   
  308. nullint      db   0cfh            ; IRET instruction
  309. exitrout     dw   exit            ; exit routine, modified if XMS, VCPI
  310.  
  311. ;=============================================================================
  312. ; 16 bit DPMI system data
  313.  
  314.                   align dword
  315. d16_Fast16_To_32          dd      ?   ; switch from 16bit to 32bit 
  316. d16_SaveRestoreState      dd      ?   ; save/restore state addr
  317.                   align word
  318. d16_EnterDPMI     dw      ?,? ; DPMI switch to protected mode (16bit)
  319. d16_SavStackOfs   dw      ?   ; current saved stack offset
  320. d16_SavStackSeg   dw      ?   ; current saved stack segment
  321. d16_PSPSel        dw      ?   ; PSP selector (use it in prot. mode)
  322. d16_DosEnvSegSel  dw      ?   ; ENVIRONMENT selector
  323.  
  324. d16_nintoff dw d32_irq0,d32_irq1,d32_irq2,d32_irq3,d32_irq4,d32_irq5,d32_irq6,d32_irq7
  325.             dw d32_irq8,d32_irq9,d32_irqa,d32_irqb,d32_irqc,d32_irqd,d32_irqe,d32_irqf
  326.             dw d32_int33,d32_int32
  327.             
  328. ;-----------------------------------------------------------------------------
  329. ; 16bit VCPI system data
  330.  
  331. ; VCPI EMS DATA
  332.  
  333. ; VCPI PAGE DIRECTORY DATA
  334.                   align word
  335. v16_PageDirSeg    dw      ?             ; seg of page directory
  336. v16_PageBase      dw      0             ; first page of himem (*4)+1000h
  337. v16_PageTop       dw      0             ; top page of himem (*4)+1000h
  338.  
  339. ;------------------------------------------------------------------------------
  340.                   align word
  341.                   ; VCPI mode-switch data
  342. v16_sw_cr3        dd      ?               ; new CR3 for 386P (physical)
  343. v16_sw_gdtaddrptr dw      s16_GDTaddr,0   ; ptr to GDT data for 386P
  344. v16_sw_idtaddrptr dw      s16_IDT32addr,0 ; ptr to IDT data for 386P
  345. v16_sw_ldtsel     dw      0               ; don't need LDTs
  346. v16_sw_trsel      dw      30h             ; task state segment selector
  347. v16_sw_dest       dd      ?               ; start in 386P EIP
  348.                   dw      20h             ; start in 386P CS            
  349.                   
  350. v16_b0b1b2b3      dw      000Ah  ; Ah! 
  351.  
  352. v16_VCPIsys       dd offset v16_sw_cr3         
  353.  
  354. ;----------------------------------------------------------------------------
  355. ; 16 bit POWER mode system data
  356.  
  357.                 align word
  358.                 
  359. s16_IDT32addr   dw      19fh, ?,?    ; 32bit IDT address,limit
  360. s16_GDTaddr     dw      04fh, GDT,0  ; 32bit GDT address,limit
  361.  
  362. s16_OldPICInt          dw   7008h  ; old PIC vals, maybe modified in VCPI
  363. s16_Int_to_replace_ctr db   33h    ; number of int vects needed -1, ditto
  364.  
  365. ; Warning! this data is packet into 16bit words!!!!
  366. ; (Oh! What i do to gain memory space)
  367. s16_idt32handler  dw   s32_irq0,s32_irq1,s32_irq2,s32_irq3,s32_irq4,s32_irq5
  368.                   dw   s32_irq6,s32_irq7,s32_irq8,s32_irq9,s32_irqa,s32_irqb
  369.                   dw   s32_irqc,s32_irqd,s32_irqe,s32_irqf
  370.                   dw   s32_int33,s32_int32,s32_int31
  371.                   dw   s32_exc0,s32_exc1,s32_exc2,s32_exc3,s32_exc4,s32_exc5
  372.                   dw   s32_exc6,s32_exc7,s32_exc8,s32_exc9,s32_exca,s32_excb
  373.                   dw   s32_excc,s32_excd,s32_exce
  374.                   align dword
  375.                   
  376.         ; table containing interrupt vectors as found at 386P initialization          
  377. _OldInt dd 0
  378.         dd 256 dup(0)
  379.                   
  380.                   align byte        
  381. ;------------------------------------------------------------------------------
  382.  
  383. InitAlloc:  
  384.         ; Allocate low memory or abort. (called from initialization code)
  385.     ; EAX=space to allocate
  386.         add eax,ds:_LoMemBase
  387.         mov ebx,ds:_LoMemTop
  388.         cmp eax,ebx            ; gone above _LoMemTop ?
  389.         ja short noinitmem     ;
  390.         mov ecx,eax
  391.         xchg eax,ds:_LoMemBase
  392.         sub ebx,ecx
  393.         cmp ebx,LOWMIN*1024  ; gone above lower memory limit of
  394.         jb short noinitmem   ; free memory reserved for program data ?
  395.         ret
  396. noinitmem:
  397.     mov dx,offset em1_no_lomem
  398. ; join error report & exit routine
  399. exit16err:
  400.         mov ah,09       ; Tell what's gone wrong and get out
  401.     int 21h
  402.         mov dx,offset emX_stderr
  403.     mov ah,09
  404.     int 21h
  405.     jmp exitrout
  406.  
  407. exit:   ; Good Old terminate program function (default exitrout)
  408.         ; for real mode termination or the final VCPI shutdown
  409.         ; (DPMI shutdown goes thru a different route)
  410.         ; restore interrupts before getting out
  411.         say msg_rints
  412.         mov si,offset _OldInt
  413.         mov ax,02500h
  414.         push ds
  415. setints:
  416.         mov dx,cs:[si]
  417.         add si,2
  418.         mov ds,cs:[si]
  419.         add si,2
  420.         int 21h
  421.         inc al
  422.         jnz setints        
  423.         pop ds
  424.         say msg_type
  425.         ; restore default typematic rate
  426.         ; now set typematic rate to the default values
  427.         mov ax,0305h ; typematic_rate set_rate
  428.         mov bx,000Ch ; 00 == 250msec delay_value  0C == 10char/sec repeat_rate
  429.         int 16h        
  430.         sti
  431.         say msg_end
  432.         mov ax,4c00h ; terminate this program
  433.     int 21h
  434.  
  435. ; 16 bit common system code starts here
  436.  
  437. ; INTREAL  & CALLREAL
  438. ; temporary INT to real mode OR temporary CALL FAR to real mode.
  439. ; CALLS TO INTREAL OR CALLREAL ARE PERFORMED FROM CODE32 SWITCHPOINTS
  440. ; SO WHEN THE CPU GETS HERE THE MODE SWITCH HAS ALREADY BEEN DONE.
  441.  
  442. intreal:  ; temporary int to real mode , NOW WE ARE In 16bit mode
  443.         cli   ; disable interrupts, they will stay disabled
  444.               ; even after the call to the real mode int
  445.         pushf ; save flags
  446.         push cs              ; push RETURN address on stack
  447.         push offset ir_done  ; to get back from real mode
  448.         mov eax,cs:tempaddr               ;
  449.         push dword ptr cs:[eax*4+_OldInt] ; push old int address seg:ofs
  450.         mov fs,cs:V86fs         ; load Vregs
  451.         mov gs,cs:V86gs         ;
  452.         mov eax,cs:V86eax       ;
  453.         mov ecx,cs:V86ecx       ;
  454.         mov edx,cs:V86edx       ;
  455.         mov ebx,cs:V86ebx       ;
  456.         mov esi,cs:V86esi       ;
  457.         mov edi,cs:V86edi       ;
  458.         mov ebp,cs:V86ebp       ;
  459.         cli   ; interrupts will need int flag disabled
  460.         retf  ; this retf jumps to the seg:ofs in tempaddr
  461. ir_done:
  462.         pushf       ; save returned flags
  463.         pop cs:V86F ;
  464.         mov cs:V86eax,eax
  465.         mov cs:V86ecx,ecx
  466.         mov cs:V86edx,edx
  467.         mov cs:V86ebx,ebx
  468.         mov cs:V86esi,esi
  469.         mov cs:V86edi,edi
  470.         mov cs:V86ebp,ebp
  471.         mov cs:V86ds,ds
  472.         mov cs:V86es,es
  473.         mov cs:V86fs,fs
  474.         mov cs:V86gs,gs
  475.         jmp IREAL_TERMINATOR
  476.         
  477. callreal: ; temporary far call to real mode , NOW in 16bit mode
  478.         push cs              ; push RETURN address on stack
  479.         push offset ic_done  ; to get back from real mode
  480.         mov fs,cs:V86fs         ; load Vregs
  481.         mov gs,cs:V86gs         ;
  482.         mov eax,cs:V86eax       ;
  483.         mov ecx,cs:V86ecx       ;
  484.         mov edx,cs:V86edx       ;
  485.         mov ebx,cs:V86ebx       ;
  486.         mov esi,cs:V86esi       ;
  487.         mov edi,cs:V86edi       ;
  488.         mov ebp,cs:V86ebp       ;
  489.         push cs:tempaddr        ; push address to call (32 bit seg:ofs  )
  490.         sti     ; make sure interrupts are enabled
  491.         retf         ; this retf jumps to the seg:ofs in tempaddr
  492. ic_done: 
  493.         cli    ; disable interrupts on return
  494.         pushf       ; save flags
  495.         pop cs:V86F ;
  496.         mov cs:V86eax,eax
  497.         mov cs:V86ecx,ecx
  498.         mov cs:V86edx,edx
  499.         mov cs:V86ebx,ebx
  500.         mov cs:V86esi,esi
  501.         mov cs:V86edi,edi
  502.         mov cs:V86ebp,ebp
  503.         mov cs:V86ds,ds
  504.         mov cs:V86es,es
  505.         mov cs:V86fs,fs
  506.         mov cs:V86gs,gs
  507. IREAL_TERMINATOR:
  508.         mov al,cs:_386Man
  509.         or  al,al      ; VCPI ?
  510.         jne irToDPMI32        
  511.         
  512. irToVCPI32:                              ; VCPI return to 386P
  513.         mov eax,offset s32_int3_d        ; jump to end of 386P INT32/33
  514.         jmp VCPI_SWITCH
  515.         
  516. irToDPMI32: ; DPMI return to 386P
  517.         mov ebx,cs:d32_SavStackOfs ;
  518.         mov dx,cs:d32_SavStackSel  ; get 386P stack in dx:ebx
  519.         
  520.         mov cx,dx                  ; cx  = current stack seg. (same of 386P)
  521.         mov si,cs:_SelCode         ; si  = new code sel
  522.         mov edi,offset d32_16done  ; edi = new code offset
  523.         mov ax,cs:_SelData         ; ax  = new data sel
  524.         jmp cs:d16_Fast16_To_32    ; mode switch routine
  525.  
  526.  
  527. ;=============================================================================
  528. ; SET INT SLOTS TABLE
  529. ; BL=low PIC val, BH=high PIC val, DI->int slot table
  530. ; THE FIRST  16 INT SLOTS ARE THE IRQ INT SLOTS
  531.  
  532. setintslots:  ; set int slot table
  533.         push cx
  534.         mov cx,8
  535. setpicints:
  536.         mov [di],bl
  537.         mov [di+8],bh
  538.         inc di
  539.         add bx,0101h
  540.         loop setpicints
  541.         pop cx
  542.         ret
  543.         
  544. ;==============================================================================
  545. ; 16 bit DPMI system code
  546.  
  547.  
  548. REAL_VCPI_DPMI_INT32: ; DPMI/VCPI REAL MODE INT32: EDX=offset to call
  549.     pushad
  550.         push ds 
  551.         push es 
  552.         push fs 
  553.         push gs
  554.         
  555.         pushfd ; push 32bit flag dword
  556.     cli
  557.     mov ax,cs
  558.     mov ds,ax
  559.     mov ds:tempaddr,edx
  560.         pop eax ; restore 32bit flag dword
  561.         and eax,512                 ; select bit 9 (interrupt flag)
  562.         mov ds:DV_INT32INTFLAG,eax  ;  stick it into the switch flag
  563.         
  564.         push d16_SavStackOfs
  565.         push d16_SavStackSeg
  566.         movzx ebx,ds:nextmodestack
  567.         lea eax,[ebx-STACKSLOT*16]
  568.         mov ds:nextmodestack,ax
  569.         add ebx,ds:StackBaseAddress
  570.         sub sp,ds:d32_StateBufferSize
  571.         mov d16_SavStackOfs,sp
  572.         mov d16_SavStackSeg,ss
  573.         
  574.         ; VCPI/DPMI 
  575.         cmp cs:_386Man,IS_VCPI
  576.         je VCPI_Int32_From_Real_Mode
  577. ; DPMI_Int32_From_Real_Mode:        
  578.         mov ax,ss
  579.         mov es,ax
  580.         mov di,sp
  581.         xor al,al
  582.         call d16_SaveRestoreState
  583.         mov ax,ds:_SelData
  584.         mov cx,ax
  585.         mov dx,ax
  586.         mov si,ds:_SelCode
  587.         mov edi,offset d32_call386P
  588.         jmp d16_Fast16_To_32
  589. DPMI_Return_Int32R:
  590.         mov di,sp
  591.         mov al,1
  592.         call d16_SaveRestoreState
  593.         add sp,ds:d32_StateBufferSize
  594. ;-----------------------------------------------------------------------------
  595. DONE_INT32R_DPMI_VCPI:                              ; done from DPMI or VCPI
  596.         pop d16_SavStackSeg
  597.         pop d16_SavStackOfs
  598.         add ds:nextmodestack,STACKSLOT*16
  599.         pop gs 
  600.         pop fs 
  601.         pop es 
  602.         pop ds
  603.         popad
  604.         iret
  605.         
  606. ;--------------------------------------------------------------------------        
  607. ; DPMI 16 bit TERMINATION ROUTINE
  608.  
  609. d16_retreal: ; DPMI TERMINATE
  610.  
  611.         ; Restore interrupts grabbed by DPMI interface
  612.         psay msg_rints
  613.         mov ax,0205h                   
  614.         mov edi,17 ; 16 ints for irq + int 33h & int 32h
  615. d16_int_restore:
  616.         mov bl,ds:intslotnum[di]
  617.         lea ebp,[edi*2+edi]
  618.         mov edx,dword ptr ds:d32_OldInts[ebp*2]
  619.         mov cx,word ptr ds:d32_OldInts[ebp*2+4]
  620.         int 31h
  621.     sub di,1
  622.         jnc d16_int_restore
  623.         jmp d16_exit
  624.         
  625. d16_exit16err:                            ; DPMI Exit with error message
  626.         mov ds:V86ds,code16
  627.     mov ds:V86ah,9
  628.         mov ax,0300h
  629.         mov bx,0021h
  630.         mov cx,0
  631.     mov edi,offset ds:V86edi
  632.     push ds
  633.     pop es
  634.     int 31h
  635. d16_exit:                                 ; DPMI exit to real mode
  636.         mov es,d16_PSPSel                 ; restore env selector
  637.         mov ax,d16_DosEnvSegSel
  638.     mov es:[2ch],ax
  639.  
  640.         ; TERMINATE PROGRAM
  641.         ; but restore interrupts before getting out
  642.         ; using the DPMI API function
  643.         mov si,offset _OldInt
  644.         mov ax,02501h
  645.         mov bl,00
  646. dsetints:
  647.         mov dx,cs:[si]
  648.         add si,2
  649.         mov cx,cs:[si]
  650.         add si,2
  651.         int 31h
  652.         inc bl
  653.         jnz dsetints        
  654.         ; Now terminate program
  655.         sti
  656.         psay msg_type
  657.         push es
  658.         ; Restore default typematic rate
  659.         mov ds:V86ax,0305h ; typematic_rate set_rate
  660.         mov ds:V86bx,000Ch ; 00 = 250msec delay_value  0C = 10char/sec repeat_rate
  661.         mov bx,0016h
  662.         mov cx,0
  663.         mov ax,300h
  664.         mov es,cs:_SelData
  665.         mov edi, offset code32:V86edi
  666.         int 31h
  667.         pop es      
  668.         psay msg_end  
  669.         ; la chiamata diretta alla funzione 4ch produceva dei casini
  670.         ; stranissimi sotto windows, quindi...
  671.         mov ax,4c00h
  672.         int 21h        
  673.  
  674. StartDPMI:  ; DPMI initialization
  675.     or ds:_386Man,IS_DPMI           ; set system type DPMI byte
  676.  
  677.     test bl,1                       ; must be 32bit DPMI
  678.     mov dx,offset em7_noDPMI32      ;
  679.     jz exit16err                    ;
  680.         mov d16_EnterDPMI[0],di ; store enter protected mode addr
  681.         mov d16_EnterDPMI[2],es ;
  682.  
  683.         push word ptr fs:[2ch]   ; preserve environment segment
  684.                                  ; located into PSP
  685.  
  686.     ; NOW GET READY TO ENTER 16BIT PROTECTED MODE
  687.     ; remember, SI = paragraphs needed for DPMI private data
  688.  
  689.     movzx eax,si      ; get mem for DPMI block
  690.     shl eax,4         ;
  691.     call InitAlloc    ;
  692.     shr eax,4         ;
  693.     add ax,code32     ;
  694.     mov es,ax         ; es:0000 = base of DPMI private data
  695.  
  696.         mov ax,0001h      ; This is a 32bit application
  697.                           ; so turn on 32bit register interface
  698.                           
  699.         call dword ptr d16_EnterDPMI   
  700.         
  701.     ; NOW IN 16 BIT PROTECTED MODE
  702.         ; PSP:[2ch] now is a SELECTOR to the environment space
  703.         ; cs,ds,ss are now SELECTORS equivalent to their 
  704.         ; previous real-mode segment values.
  705.         ; es conatins the PSP selector
  706.         ; fs,gs are set to zero
  707.         
  708.         cli ; Better don't trust DPMI , clear interrupts again
  709.  
  710.     mov dx,offset em8_DPMIdesc    ;
  711.     jc exit16err                  ; Got a descriptor ?
  712.  
  713.         mov ds:V86dx,dx   ; prepare for abort if any error lurks 
  714.  
  715.         pop ax             ; swap old16_env16_seg with selector
  716.         xchg ax,es:[2ch]   ; now pspa+2ch == environment REAL segment
  717.                            ; we use this trick because VCPI,XMS&POWER
  718.                            ; startup code doesn't set up selectors for PSP
  719.  
  720.         mov d16_DosEnvSegSel,ax         ; DPMI ENVIRONMENT selector
  721.  
  722.         mov d16_PSPSel,es               ; store PSP selector
  723.  
  724.     mov ds:_EXIT_DATA_SEL,ds             ;
  725.     mov ds:_EXIT_SEL,cs                  ;
  726.         mov ds:_EXIT_OFS,offset d16_retreal  ; set program termination data
  727.  
  728.         mov ds:_SetIRQ,offset d32_setirq  ; set new IRQ managers
  729.         mov ds:_GetIRQ,offset d32_getirq  ;
  730.  
  731.         push ds    ; no more need for PSP segment
  732.         pop es     ; 
  733.  
  734.     ; MUST ASK DPMI FOR VALID SELECTORS
  735.     mov ax,0003   ; get selector increment value
  736.     int 31h       ;
  737.     mov bx,ax     ;
  738.  
  739.     mov ax,0000   ; get base selector for a list of 3 selectors
  740.         mov cx,3      ; cx= number of selector to allocate in LDT
  741.     int 31h       ;
  742.  
  743.         jc d16_exit16err
  744.     ; set up descriptors
  745.     ;  bx= selector increment  ,  ax = first selector value
  746.  
  747.     ; INITIALIZE & STORE SELECTORS
  748.         mov si,ax                       ; si = _SelCode selector
  749.         mov ds:_SelCode,ax              ;
  750.  
  751.         lea ecx,[eax+ebx]               ; cx = _SelData selector
  752.         mov ds:_SelData,cx              ;
  753.  
  754.         lea ebp,[ecx+ebx]               ; bp = _SelZero selector
  755.         mov ds:_SelZero,bp              ;
  756.  
  757.     mov ds:V86dx,offset em9_DPMImod
  758.         
  759.         ; WARNING! THIS CAN BE DANGEROUS!!! TRY ANOTHER METHOD!
  760.         mov dx,cs
  761.         lar dx,dx
  762.         and dh,060h ; access rights AND RPL 3
  763.         
  764.         ; NOW LINK THE DESCRIPTORS TO THEIR SELECTOR INTO LDT
  765.  
  766.         mov ax,000ch                      ; COPY descriptors into DPMI LDT
  767.                       ; ax = 000ch
  768.                       ; bx     = selector value
  769.                       ; ds:edi = pointer to the 8 bytes
  770.                       ;          of data to COPY into
  771.                       ;          the descriptor into GTD
  772.  
  773.     mov bx,si                         ;
  774.     mov edi,offset ds:GDTcode32       ;
  775.         or byte ptr [edi+5],dh            ; cambia livello di protezione
  776.     int 31h                           ;
  777.         jc d16_exit16err                  ;
  778.  
  779.     mov bx,cx                         ;
  780.     mov edi,offset ds:GDTdata32       ;
  781.         or byte ptr [edi+5],dh            ;
  782.     int 31h                           ;
  783.         jc d16_exit16err                  ;
  784.  
  785.     mov bx,bp                         ;
  786.     mov edi,offset ds:GDTzero32       ;
  787.         or byte ptr [edi+5],dh            ;
  788.     int 31h                           ;
  789.         jc d16_exit16err                  ;
  790.         
  791.         ; SET EXTRA SEGMENT REGISTERS
  792.         mov es,cx    ;
  793.         mov fs,cx    ; ES,FS = Data32 (alias for Code32)
  794.         
  795.         mov gs,bp    ; GS = linear addressing base
  796.         
  797.  
  798.     ; CHECK IF THERE IS ENOUGH LOW MEMORY FOR PROGRAM DATA
  799.     ; AND DMPI TABLES
  800.         mov edi,ds:_LoMemBase
  801.         mov eax,ds:_LoMemTop
  802.     sub eax,edi
  803.         cmp eax,128  ; minimum space needed for extended info
  804.     mov ds:V86dx,offset em1_no_lomem
  805.         jb d16_exit16err
  806.          
  807.         mov ds:_HiMemBase,0  ; better assume the worst
  808.         mov ds:_HiMemTop ,0
  809.         
  810.         mov eax,(EXTMIN)
  811.         or eax,eax
  812.         jz rumblefish ; if no ext. mem required, go to set DPMI_state
  813.         
  814.         ; DPMI 00.90  ext. memory allocation
  815.         ; initially my code checked for DPMI version numbers
  816.         ; but found some inconsistent major release numbers
  817.         ; so decided to support only the lowest common denominator (DPMI 0.9)
  818.         mov ax,0500h             ;  ax     = 0500 == GET DPMI INFO 0.9
  819.         int 31h                  ;  es:edi = info block  (48 bytes wide)
  820.  
  821.         mov edx,es:[edi+08h]  ; largest available lockable page number
  822.         cmp edx,-1            ; (1page = 4K)
  823.         je  short DPMIdefault_alloc
  824.         ; UNCOMMENT this code if you don't like the extra debug messages
  825.         ; and think you can live with 128k less
  826.         ;cmp edx,33
  827.         ;jb short DPMIdefault_alloc
  828.         ; sub edx,32 ; leave 128k free to system usage
  829.         shl edx,12 ; allocate lockable pages
  830.         jmp short DPMIbyte_alloc
  831. DPMIdefault_alloc:        
  832.         mov edx,(EXTMIN*1024)  ; minimum space in Kbyte
  833. DPMIbyte_alloc:
  834.         mov ds:V86dx,offset em3_no_himem
  835.         cmp edx,(EXTMIN*1024)
  836.         jb d16_exit16err
  837.  
  838.         or edx,edx  ; zero bytes available ? go to next section
  839. rumblefish: ; rumblefish and ZERO FLAG from above !!!!!! :) 
  840.         jz short to_DPMI_state    ; no need for extended memory
  841.         
  842.         ; ALLOCATE EXT. MEMORY THRU DPMI
  843. d16_winbumper:  
  844.         psay msg_DPMImem
  845.         push edx      
  846.     mov cx,dx                         ; in:
  847.         shld ebx,edx,16                   ; ax = 0501
  848.     mov ax,0501h                      ; bx:cx = ext. memory needed
  849.     int 31h                           ; out:
  850.         jnc d16_works                     ; CARRY CLEAR == NO ERRORS and ...
  851.     mov ds:V86dx,offset em5_hifault   ; bx:cx = linear address allocated
  852.                                           ; si:di = memory block handle
  853.         ; Aw! Something has gone wrong! 
  854.         pop edx
  855.         cmp edx,(EXTMIN*1024)
  856.         jbe d16_exit16err
  857.         sub edx,4096     ; try one page less, and see if it works
  858.         
  859.         jmp d16_winbumper ; Usually Windows is to blame for this!
  860. to_DPMI_state:
  861.         ; Don't touch this!!!!!!!!!
  862.         jmp short DPMI_state        
  863. d16_works:
  864.         pop edx  ; restore & save again requested memory
  865.         push edx ;
  866.         pushad           ; try to lock all the memory you can get
  867.         mov di,dx        ; but don't care if you fail
  868.         shld esi,edx,16  ; (i do this just to reduce disk swapping)
  869.         mov ax,0600h     ; if you wan to do serious irq handling into
  870.         int 31h          ; extende memory or want to DMA things
  871.         popad            ; you'd better relock the regions you use
  872.         psay msg_DPMIwin
  873.         pop edx
  874.         shl ebx,16               ;
  875.         mov bx,cx                ;  ebx = memory block linear address
  876.         sub ebx,ds:_Code32Base   ;
  877.         mov ds:_HiMemBase,ebx    ;
  878.     add ebx,edx              ;
  879.         mov ds:_HiMemTop,ebx     ;  SET EXT MEM LIMITS
  880.  
  881. DPMI_state:
  882.         ; ALLOCATE DPMI_SAVE_TASK_STATE BUFFERS AND POINTERS
  883.  
  884.     mov ax,0305h  ; get save/restore state addresses
  885.     int 31h       ;
  886.  
  887.         mov ds:d32_StateBufferSize,ax  ; leght of save state block
  888.  
  889.     ; 32bit save/restore state  protected-mode routine
  890.         mov dword ptr ds:d32_SaveRestoreState[0],edi ; offset32
  891.         mov  word ptr ds:d32_SaveRestoreState[4],si  ; seg32
  892.  
  893.     ; 16 bit save/restore state real-mode routine
  894.         mov word ptr d16_SaveRestoreState[0],cx  ; offset16
  895.         mov word ptr d16_SaveRestoreState[2],bx  ; seg16
  896.  
  897.     ; SET MODE SWITCH CODE POINTERS
  898.  
  899.     mov ax,0306h  ; get raw Mode Switch to 16<-->32 bit mode
  900.     int 31h       ;
  901.  
  902.     ; switch protected->real mode routine
  903.         mov dword ptr ds:d32_Fast32_To_16[0],edi ; offset 32
  904.         mov  word ptr ds:d32_Fast32_To_16[4],si  ; seg32
  905.  
  906.     ; switch real->protected mode routine
  907.         mov word ptr d16_Fast16_To_32[0],cx ; offset16
  908.         mov word ptr d16_Fast16_To_32[2],bx ; seg16
  909.  
  910.     ; NOW SET IRQs & INTs
  911.  
  912.     ; set IRQ handlers to PIC values
  913.     mov ax,0400h ; Get DPMI version info
  914.     int 31h      ; dh = 1st PIC base vector dl= 2nd PIC base vector
  915.  
  916.     mov di,offset ds:intslotnum   ;
  917.     xchg dl,dh                    ;
  918.     mov bx,dx                     ;
  919.     call setintslots              ; set new vector table for IRQ
  920.         psay msg_DPMIirq
  921.         mov ah,02                     ; backup and set all int vectors
  922.         mov si,ds:_SelCode            ;
  923.         mov edi,17                    ;
  924.         
  925. DPMI_SavSetInts:
  926.         mov bl,ds:intslotnum[di]   ;
  927.         mov al,04                  ; ah was 02, so execute function 0204h
  928.         int 31h                    ; GET INT VECTOR bl
  929.         
  930.         lea ebp,[edi*2+edi]
  931.         mov dword ptr ds:d32_OldInts[ebp*2],edx
  932.         mov word ptr ds:d32_OldInts[ebp*2+4],cx
  933.         
  934.         mov al,05                  ;
  935.         movzx edx,d16_nintoff[edi*2] ; ah was 02, so execute function 0205h
  936.         mov cx,si                  ; SET INT VECTOR bl
  937.     int 31h                    ;
  938.         
  939.         sub di,1
  940.         jnc DPMI_SavSetInts
  941.  
  942.         ; DPMI GOES TO 32bit INIT STUFF
  943.         push es  ; set up needed regs & go on to 32bit!
  944.         pop ss
  945.         add esp,ds:StackBaseAddress
  946.         jmp JoinDPMI
  947.         
  948. ;-----------------------------------------------------------------------------
  949. ; 16bit VCPI system code
  950.  
  951. v16_retreal: ; VCPI return to real mode ( called from _Exit routine)
  952.         ; conversione ESP da 32bit a 16bit, risultato in EBX
  953.         mov ebx,esp
  954.         sub ebx,ds:StackBaseAddress  ;ritorna all' offset valido in modo reale
  955.         
  956.         mov eax,code16
  957.         mov ecx,codeend
  958.         
  959.         ; now set-up the return environment
  960.         ; (n.b. 16bit values MUST be pushed as dwords)
  961.         push eax   ; DWORD  GS  = code16
  962.         push eax   ; DWORD  FS  = code16
  963.         push eax   ; DWORD  DS  = code16
  964.         push eax   ; DWORD  ES  = code16
  965.         push ecx   ; DWORD  SS  = codeend
  966.         push ebx   ; DWORD ESP  = translated offset
  967.         pushfd     ; DWORD EFLAGS
  968.         push eax   ; DWORD  CS  = code 16
  969.         dw 6866h,v16_retreal2,0   ; 32bit PUSH offset v16_retreal2
  970.         mov ax,gs ;
  971.         mov ds,ax ; load linear memory descriptor into DS
  972.         mov ax,0de0ch
  973.         call cs:v32_vcpientryaddr ; N.B. this is a FAR call
  974.         
  975. ;-----------------------------------------------------------------------------
  976. ; VCPI REAL MODE INT32: EDX=off
  977. VCPI_Int32_From_Real_Mode: 
  978.         mov eax,offset v32_call386P        
  979.         ; join VCPI_SWITCH
  980.         
  981. ;------------------------------------------------------------------------------        
  982. ; CALL TO 16bit prot mode  : EAX=offset to jump to in code32
  983.  
  984. VCPI_SWITCH: ; VCPI switch to protected mode from v86 mode
  985.              ; or from v86 mode to protected mode
  986.              ; (here we use the VCPI_SWITCH to go to protected mode)
  987.         mov cs:v16_sw_dest,eax       ; offset to jump at        
  988.         mov esi,cs:v16_VCPIsys   ; system data for mode switch
  989.         
  990.         mov ax,0de0ch   ; SWITCH TO 16bit PROTECTED MODE thru VCPI 
  991.         int 67h         ; 
  992.         
  993. v16_retreal2:
  994.         ; just returned to real mode from protected mode
  995.         cli        
  996.         ; if something fails, you get here ..
  997. VCPI_exit: ; VCPI exit (clean up paging stuff)
  998.         mov es,v16_PageDirSeg
  999.         mov si,v16_PageBase
  1000.         mov cx,v16_PageTop
  1001.         
  1002.         sub cx,si          ; Need to deallocate VCPI memory pages ?
  1003.         
  1004.         jz short page_cleaned  ; No! Only remove EMS data
  1005.         ; Yes! Clean pages 
  1006.         say msg_VCPIfree
  1007. VCPI_clean:  ; Deallocate memory pages allocated thru VCPI
  1008.  
  1009.         mov edx,es:[si] ;
  1010.         and dx,0f000h   ;  edx == address of 4k page to deallocate & unlink
  1011.         
  1012.         mov ax,0de05h   ;  call page unlink function
  1013.         int 67h         ;
  1014.         
  1015.         add si,4 ; next page
  1016.         
  1017.         sub cx,4        ; loop if there are other pages to clean
  1018.         jnz VCPI_clean  ;
  1019. page_cleaned: ; now go to standard exit code
  1020.         jmp exit
  1021.         
  1022. VCPI_err1: ; VCPI not enough low mem exit
  1023.         mov dx,offset em1_no_lomem
  1024.         jmp exit16err
  1025.         
  1026. ;=============================================================================
  1027.  
  1028. StartVCPI:  ; Init VCPI
  1029.         or ds:_386Man,IS_VCPI              ; set system type = VCPI 
  1030.         
  1031.         mov eax, ds:v16_VCPIsys  ; adjust linear pointer
  1032.         add eax, ds:_Code16Base  ; to switch parameters
  1033.         mov ds:v16_VCPIsys,eax   ;
  1034.         
  1035.         mov exitrout,offset exit ; set standard dos-cleanup exit
  1036.         
  1037.         ; NOW HANDLE PICs YOURSELF
  1038.         mov ax,0de0ah   ; get PIC base vector mappings
  1039.         int 67h         ; BX,CX = first vector of master PIC and slave PIC 
  1040.         mov bh,cl       ; bh= now is first vector of slave PIC
  1041.         ; N.B. A single PIC uses 8 consecutive vector numbers
  1042.         ;      so you'd better avoid to use the vector base 030h
  1043.         ;      or your interrupts will "cover" then int 31h, int32h, int 33h 
  1044.         ;      386power interface
  1045.         mov s16_OldPICInt,bx     ; save PIC base vector mappings
  1046.         
  1047.         mov dx,offset em11_EqPIC ; set error message if something goes wrong
  1048.         
  1049.         ; Check for compatible PIC mapping ...
  1050.         cmp bl,bh
  1051.         je exit16err  ; Uh? Mapped as equal ? Whats that? Are you crazy ?
  1052.                       ; I'm NOT a fucking old IBM XT
  1053.                       
  1054.         mov dx,offset em6_PICfault ; set error message if something goes wrong              
  1055.         cmp bl,30h
  1056.         je exit16err  ; Low mapping clashes with service ints
  1057.         cmp bh,30h
  1058.         je exit16err  ; High mapping clashes with service ints
  1059.         
  1060.         ; SET UP NEW P.I.C. MAPPINGS
  1061.         mov ax,70h         ; new mapping = highest_needed_int - 7
  1062.                            ; infatti  si ha 2ch+7 = 33h
  1063.         cmp al,bl           ;
  1064.         ja short HIPIC1     ; max int mapping > master pic mapping ?
  1065.         mov al,bl           ;
  1066. HIPIC1:                     ; 
  1067.  
  1068.         cmp al,bh           ; max int mapping > slave pic mapping  ?
  1069.         ja short HIPIC2     ;
  1070.         mov al,bh           ;
  1071. HIPIC2:                     ;
  1072.  
  1073.         add al,7 ; add the 7 exceptions handlers 
  1074.                  ; to get the IDT SIZE
  1075.                    
  1076.         
  1077.         mov s16_Int_to_replace_ctr,al  ;
  1078.         
  1079.         ; SET INT VECTOR TABLE
  1080.         lea eax,[eax*8+7]      ; set limit of IDT 
  1081.         mov s16_IDT32addr,ax   ; (don't, worry we use the lower 16 bits)
  1082.         ; bl,bh == int slots for master & slave PIC
  1083.         mov di,offset ds:intslotnum     ; set int slots as needed
  1084.         call setintslots                ;
  1085.         
  1086.         ; NOW ALLOCATE&INITIALIZE TSS AND IDT
  1087. VCPI_IDT_TSS:  
  1088.         ; ALLOCATE SPACE FOR TSS AND IDT
  1089.         movzx eax,s16_IDT32addr         ; get (limit -1) of IDT
  1090.         add eax,(2068h+1)               ; TSS is 68h bytes wide
  1091.                                         ; and we need extra space
  1092.                                         ; for IO bitmap
  1093.         call InitAlloc                  ; allocate space for TSS and IDT
  1094.         
  1095.         mov ds:s32_tssesp0ptr,eax ; registra TSS base address       
  1096.         
  1097.         ; eax = base of allocated block
  1098.         
  1099.         ; questa roba la faceva la prima versione di pmode 386
  1100.         mov ebp,ds:_Code32Base  ; set Task Switch Selector address
  1101.         lea ebx,[eax+ebp]               ; into GTD
  1102.         or dword ptr ds:GDTtask[2],ebx  ;
  1103.         
  1104.         add ebx,2068h                          ; set IDT base address
  1105.         mov dword ptr ds:s16_IDT32addr[2],ebx  ;
  1106.         
  1107.         mov eax,ds:_Code16Base                 ; convert GTD & IDT addresses
  1108.         add dword ptr v16_sw_gdtaddrptr,eax ; from code16-relative offsets
  1109.         add dword ptr v16_sw_idtaddrptr,eax ; to LINEAR addresses
  1110.  
  1111.         mov exitrout,offset VCPI_exit     ; set VCPI error&exit routine
  1112.         
  1113.         mov eax,ds:_LoMemBase  ; align lomem base on a 4k page
  1114.         mov ebx,ds:_Code32Base    ;
  1115.         add ebx,eax            ;
  1116.         lea ecx,[ebx+0fffh]    ;
  1117.         and ecx,0fffff000h     ; ecx == _LoMemBase as LINEAR address
  1118.         sub ebx,ecx            ;
  1119.         sub eax,ebx            ;
  1120.         mov ds:_LoMemBase,eax  ; eax == _LoMemBase as OFFSET from code32
  1121.         
  1122.         mov ebp,ds:_LoMemTop   ; get available low memory
  1123.         sub ebp,eax            ;
  1124.         sub ebp,LOWMIN*1024    ; die if not enough low memory
  1125.         jc VCPI_err1           ;
  1126.         cmp ebp,8192           ; die if no space for minimal page structure
  1127.         jb VCPI_err1           ;
  1128.  
  1129.         shr   ecx,4            ; set VCPI 386POWER page-directory segment 
  1130.         mov v16_PageDirSeg,cx    ;
  1131.         ; The 8k allocated in low memory are split into
  1132.         ; 1) a 4K (1000h) PAGE DIRECTORY 
  1133.         ; 2) a 4k PAGE TABLE (the first page table, others are chained to it)
  1134.         
  1135.         mov es,cx                   ; reset all addresses
  1136.         xor di,di                   ;
  1137.         mov cx,2048                 ;
  1138.         xor eax,eax                 ;
  1139.         rep stos dword ptr es:[di]  ;
  1140.         
  1141.         ; GET VCPI 32BIT INTERFACE
  1142.         mov di,1000h ; es:di == pointer to FIRST PAGE TABLE
  1143.                      ; (vcpi inits it with the pages already allocated)
  1144.                      
  1145.         mov si,offset ds:GDTvcpi ; Get Vcpi Protected Mode Interface
  1146.         mov ax,0de01h            ; in:    ax = 0de01h
  1147.         int 67h                  ;  es:di = ptr to 4k page table buffer
  1148.                                  ;  ds:si = ptr to 3 descriptor table entries 
  1149.                                  ;          the first becomes the
  1150.                                  ;          code segment descriptor
  1151.                                  ;          the other two are used by
  1152.                                  ;          the MAIN CONTROL PROGRAM
  1153.                                  ; out:  ebx = offset of prot. mode entry point
  1154.                                  ;             (relative to GDTvcpi)
  1155.                                  ;       es:di = first unused page table entry
  1156.                                  ;               in page table buffer
  1157.                                   
  1158.         mov dword ptr ds:v32_vcpientryaddr,ebx  
  1159.         
  1160.         ; DI = end of allocated entries on page table
  1161.         ; ONE ENTRY takes 4 bytes, one entry is a 4k page
  1162.         ; so if you subtract the page base offset (1000h)
  1163.         ; DI is EXACTLY how many Kbytes has been allocated by VCPI
  1164.         ; starting from "your task" linear address 00000000h
  1165.         
  1166.         mov v16_PageBase,di      ; set up and go through page map allocation 
  1167.         mov v16_PageTop,di       ;
  1168.         
  1169.         movzx eax,di           ;
  1170.         sub eax,1000h          ;
  1171.         shl eax,10             ;  eax = base of extended memory in bytes
  1172.         
  1173.         mov ebp,ds:_Code32Base    ;
  1174.         
  1175.         sub eax,ebp            ;
  1176.         mov ds:_HiMemBase,eax  ;  STORE INITIAL _HiMemBase 
  1177.         
  1178.         ; NOW SET EBX AS A COUNTER OF THE BYTES ALLOCATED
  1179.         ; IN LOW MEMORY FOR PAGING INFO
  1180.         mov ebx,8192           ; one page directory + one page table
  1181.         
  1182. page_table_alloc:                      
  1183.         mov ax,0de04h          ; Allocate one page, ax =0de04h
  1184.         int 67h                ; out: ah = error code ( 00 == no errors)
  1185.         or ah,ah               ;     edx = linear address of allocated page
  1186.         jnz short end_page_alloc    
  1187.         
  1188.         test di,0fffh             ; Check if at end of page table
  1189.         jnz short not_4k_boundary ;
  1190.         
  1191.         add ebx,4096           ; add space for another 4k page table
  1192.         cmp ebx,ds:_LoMemTop   ; run out of low memory ?
  1193.         ja VCPI_err1           ;
  1194.         
  1195. not_4k_boundary:                      
  1196.         and dx,0f000h          ; Mark this page as one-page-block
  1197.         or dl,7                ; (but movable if needed)
  1198.         mov es:[di],edx        ; store entry on page table
  1199.         add di,4               ;
  1200.         jns page_table_alloc   ; STOP if allocated 32Mbytes of ext. mem.
  1201.         
  1202. end_page_alloc:                         
  1203.         mov v16_PageTop,di ; Store final allocated page table limit
  1204.         
  1205.         lea si,[di-1000h] ;
  1206.         movzx eax,si      ;
  1207.         shl eax,10        ; eax = LINEAR address of allocated ext. mem. limit
  1208.         
  1209.         sub eax,ebp                ; EBP is still_Code32Base
  1210.         mov ds:_HiMemTop,eax       ; store _HiMemTop
  1211.         
  1212.         sub di,v16_PageBase          ;
  1213.         cmp di,EXTMIN              ;
  1214.         
  1215.         mov dx,offset em3_no_himem
  1216.         jb exit16err
  1217.         
  1218.         add ds:_LoMemBase,ebx      ;
  1219.         
  1220.         ; QUELLO CHE SEGUE ERA ASSAI SOSPETTO !!!!!
  1221.         ; HO DOVUTO CODIFICARE TUTTO "A NASO" confidando
  1222.         ; che i progettisti di VCPI non siano delle teste a pera.
  1223.         
  1224.         movzx eax,v16_PageDirSeg ; 
  1225.         shl   eax,4              ; page_dir segment as linear address
  1226.         
  1227.         mov   ebx,1000h   ; PAGE SIZE
  1228.         
  1229.         mov v16_sw_cr3,eax                ; SET PAGE REGISTER
  1230.         
  1231.         ; NOW IT'S TIME TO INITIALIZE THE PAGE DIRECTORY
  1232.         ;
  1233.         xor di,di   ; es:di == page directory address                    
  1234. set_page_directory:
  1235.         add eax,ebx ; prossima page table
  1236.         and ax,0f000h    ; Why this ? A MISTERY to me!
  1237.         or al,7          ; Looks like we have to set paging info stored
  1238.         stosd            ; into page table location on page dir. entry
  1239.         sub si,bx ; 4Mbytes has been mapped in a single page dir entry
  1240.         ja set_page_directory
  1241.  
  1242.         ; NOW PATCH DOS EXTENDED CODE FOR VCPI
  1243.         mov ebx,ds:s32_tssesp0ptr
  1244.         mov eax,offset VCPI_protected16 ; offset to jump to in 386P
  1245.         jmp VCPI_SWITCH                 ; BANG! HERE WE GO PROTECTED
  1246.         
  1247. VCPI_protected16:        ; in 16bit prot. mode
  1248.         ; Now set 32 bit protected mode segments and stack pointer
  1249.         ; for VCPI
  1250.         ; (DPMI uses the selectors allocated from the DPMI server)
  1251.         
  1252.         mov ax,28h ;
  1253.         mov ds,ax  ;  ds= data16
  1254.         
  1255.         mov al,18h ;
  1256.         mov gs,ax  ; gs= linear
  1257.         
  1258.         mov al,10h ;  es,fs,ss = data32
  1259.         mov es,ax  ;
  1260.         mov fs,ax  ;
  1261.         mov ss,ax  ;
  1262.         
  1263.         mov esp,STACKSIZE*16      ; stack size
  1264.  
  1265.         add esp,ds:StackBaseAddress  ; esp = prot. mode stack base
  1266.         ; now in 32bit mode
  1267. VCPI_set_TSS_data:
  1268.         ; ebx = address of TSS ( code32 relative )
  1269.         ; new FROM PMODE24
  1270.         
  1271.         ; First switch was from code16 to code16
  1272.         ; next switches will be from code16 to code32
  1273.         
  1274.         lea eax,[ebx+4]             ; eax = address of ESP0 in TSS
  1275.         mov ds:s32_tssesp0ptr,eax   ; store pointer to ESP0
  1276.                                     ; (needed for VCPI task switchers)
  1277.         mov es:[eax],esp                            
  1278.         
  1279.         ; remember: ds== data16   es==data32
  1280.         
  1281.         ; set up TSS stuff (EBX == TSS base)
  1282.         
  1283.         ; dword ptr, come mai ????
  1284.         mov dword ptr es:[ebx+8],10h  ; set SS of CPL0
  1285.         
  1286.         mov edi,104  ; 104 == 68h == fine del TSS
  1287.         mov es:[ebx+102],di
  1288.         mov word ptr es:[ebx+100],0
  1289.         
  1290.         add edi,ebx     ; Fill IO bitmap with 0
  1291.         xor eax,eax     ; If it works for Tran, it works for me too!
  1292.         mov ecx,800h    ; (i've already tried without this)
  1293.         rep stosd       ;
  1294.         
  1295.         ; non mi sembra che fare una cosa del genere sia salutare
  1296.         ;mov cx,30h
  1297.         ;ltr cx
  1298.         
  1299.         ; riprende il vecchio codice
  1300.         
  1301. VCPI_ready32:
  1302.         ; First switch was from code16 to code16
  1303.         ; next switches will be from code16 to code32
  1304.         mov word ptr v16_sw_dest[4],8     
  1305.         
  1306.         mov ecx,offset s16_idt32handler   ; int handler table
  1307.         
  1308.         mov edi,dword ptr s16_IDT32addr[2]; get ptr to IDT
  1309.         sub edi,ds:_Code32Base               ; get 
  1310.         
  1311.         ; Common code for final initialization
  1312.  
  1313.         ; now inizialize IDT with general exception handler
  1314.         
  1315.         mov   ds:s32_idt32ptr,edi      
  1316.         ; now EDI == base pointer to IDT32
  1317.         ;     ECX == base pointer to IDT16
  1318.         
  1319.         ; set general excpection handlers
  1320.         movzx esi,s16_Int_to_replace_ctr
  1321.         
  1322.         mov eax,offset s32_excf ;
  1323.         and eax,0000ffffh       ; parte bassa offset s32_excf
  1324.         add eax,00080000h       ; selettore codice
  1325.         
  1326.         mov ebp,00008E00h       ; flags & parte alta offset azzerata
  1327.                                 ; (tanto il nucleo e' al di sotto dei 64k)
  1328.                                 ; e' uno sporco trucco ... ma mi piace!
  1329.                                 
  1330.         ; Struttura di una IDT entry (8 bytes)
  1331.         ; offset  size
  1332.         ;      0     2   parte bassa offset ISR (Interrupt Service Routine)
  1333.         ;      2     2   selettore segmento ISR     
  1334.         ;      4     2   flags vari
  1335.         ;      6     2   parte alta  offset ISR
  1336.         
  1337. SetIDTEntry:
  1338.         ; selettore = 8 
  1339.         ; offset    = offset s32_excf  (handler generalizzato)
  1340.         mov dword ptr   es:[edi+esi*8],eax ; offset basso e selettore
  1341.         mov dword ptr es:[edi+esi*8+4],ebp ; flags & offset alto azzerato
  1342.         dec si        ; WARN
  1343.         jns SetIDTEntry
  1344.         
  1345.         ; copy exception handlers from IDT
  1346.         mov esi,33
  1347. SetIDTInt:
  1348.         movzx ebp,byte ptr ds:intslotnum[si]
  1349.         mov ax,[ecx+esi*2]    ; prendi l' offset dell' ISR da s16_idt32handler
  1350.         mov es:[edi+ebp*8],ax ; scrivilo
  1351.         dec si       ; WARN
  1352.         jns SetIDTInt
  1353.         
  1354.         ; HERE WE GO TO 32bit PROTECTED MODE
  1355.         pushfd               ; set eflags: NT=0, IOPL=3
  1356.         pop eax
  1357.         and ah,0bfh
  1358.         or ah,30h
  1359.         push eax
  1360.         popfd
  1361.  
  1362. ; READY TO ENTER 32BIT PROTECTED MODE
  1363.  
  1364. JoinDPMI: ; shared by VCPI & DPMI
  1365.           ; NOW WE CAN ENTER 32BIT PROTECTED MODE
  1366.         push es
  1367.         pop ds
  1368.         push dword ptr cs:_SelCode  ;
  1369.         push offset INIT_386P       ;
  1370.         db 66h,0cbh                 ; 32bit RETF go to 32bit stuff
  1371.  
  1372. ; =========================
  1373. ; NATIVE 16 bit system code
  1374. ; =========================
  1375.  
  1376. s16_irqreal:         ; native 386 real mode IRQ from 32bit prot. mode
  1377.         pushf
  1378.         push cs
  1379.         push offset IREAL_TERMINATOR
  1380.         mov eax,cs:tempaddr
  1381.         jmp cs:[eax*4+_OldInt]
  1382.         
  1383. code16  ends
  1384.  
  1385. ; 32bit code
  1386. code32  segment para public use32
  1387.         assume cs:code32, ds:code32
  1388.         org 0
  1389.  
  1390. extrn   _Main:near
  1391.  
  1392. public  _Exit, _GetMem, _GetLoMem, _GetHiMem
  1393. public  _GetIRQMask, _SetIRQMask
  1394.  
  1395. public  V86eax, V86ebx, V86ecx, V86edx, V86esi, V86edi, V86ebp
  1396. public  V86ax, V86bx, V86cx, V86dx, V86si, V86di, V86bp
  1397. public  V86al, V86ah, V86bl, V86bh, V86cl, V86ch, V86dl, V86dh
  1398. public  V86ds, V86es, V86fs, V86gs
  1399. public  _SelCode, _SelData, _SelZero, _LoMemBase, _LoMemTop, _HiMemBase
  1400. public  _HiMemTop, _PSPBase, _Code16Base, _Code32Base, _GetIRQ, _SetIRQ
  1401. public  _386Man
  1402.  
  1403. ; 32 bit common system data
  1404.  
  1405.                 dd      ?               ; scratch dword for VCPI tss esp0
  1406.                 align dword
  1407. _LoMemBase      dd      0               ; low mem base for allocation
  1408. _LoMemTop       dd      0               ; top of low mem
  1409.  
  1410. _HiMemBase      dd      0               ; high mem base for allocation
  1411. _HiMemTop       dd      0               ; top of high mem
  1412.  
  1413. _PSPBase           dd      ?               ; LINEAR offset of start of PSP 
  1414. _Code16Base        dd      ?               ; LINEAR offset of start of 16bit code 
  1415. _Code32Base        dd      ?               ; LINEAR offset of start of 32bit code 
  1416.  
  1417. _GetIRQ     dd      s32_getirq       ; get IRQ handler offset routine addr
  1418. _SetIRQ     dd      s32_setirq       ; set IRQ handler offset routine addr
  1419.  
  1420.                 align word
  1421. _SelCode        dw      8               ; code segment selector
  1422. _SelData        dw      10h             ; data segment alias for code
  1423. _SelZero        dw      18h             ; data segment starting at 0:0
  1424.  
  1425.  
  1426.                 align byte
  1427. ; Global Descriptors Table
  1428. GDT           dq      0                           ; selettore 00h
  1429. GDTcode32     db      0ffh,0ffh,0,0,0,9ah,0cfh,0  ;           08h  
  1430. GDTdata32     db      0ffh,0ffh,0,0,0,92h,0cfh,0  ;           10h
  1431. GDTzero32     db      0ffh,0ffh,0,0,0,92h,0cfh,0  ;           18h
  1432. GDTcode16     db      0ffh,0ffh,0,0,0,9ah,0,0     ;           20h
  1433. GDTdata16     db      0ffh,0ffh,0,0,0,92h,0,0     ;           28h
  1434. GDTtask       db      0ffh,0ffh,0,0,0,89h,0,0     ;           30h
  1435. GDTvcpi       dq      3 dup(?)                    ;  38h,40h,48h
  1436.               ;  il selettore 38h e' quello della GDT
  1437.               ;  il selettore 40h e' un data segment sulla pagina zero
  1438.               ;  il selettore 48h e' un segmento dati a 32bit
  1439.               
  1440. ; Virtual 8086 Registers
  1441. V86edi        label   dword      ; vregs for 386P<-->V86 communication
  1442. V86di         dw      0, 0       ; we need this order if we want
  1443. V86esi        label   dword      ; to bypass 386POWER and go thru DPMI API
  1444. V86si         dw      0, 0       ;
  1445. V86ebp        label   dword      ; I'm planning to support more than
  1446. V86bp         dw      0, 0       ; DPMI 900h 901h & 902h 
  1447.               dd      0          ; if DPMI becomes prevalent.
  1448. V86ebx        label   dword
  1449. V86bx         label   word
  1450. V86bl         db      0
  1451. V86bh         db      0, 0,0
  1452. V86edx        label   dword
  1453. V86dx         label   word
  1454. V86dl         db      0
  1455. V86dh         db      0, 0,0
  1456. V86ecx        label   dword
  1457. V86cx         label   word
  1458. V86cl         db      0
  1459. V86ch         db      0, 0,0
  1460. V86eax        label   dword
  1461. V86ax         label   word
  1462. V86al         db      0
  1463. V86ah         db      0, 0,0
  1464. V86F          dw      0
  1465. V86es         dw      0
  1466. V86ds         dw      0
  1467. V86fs         dw      0
  1468. V86gs         dw      0
  1469.               dd      0,0
  1470.  
  1471. OldBreakISR     dd      ?               ; old int 1Bh  (ctrl+break)
  1472. OldIRQMask      dw      ?               ; old port 21h and 0a1h masks
  1473.  
  1474.                 align byte
  1475.                 
  1476. _386Man         db      0               ; system bits:
  1477.                                         ;  bit 1: 0=VCPI, 1=DPMI                
  1478.                                         
  1479. intslotnum      db      16 dup(0)
  1480.                 ; 16 int vectors for the two PICs
  1481.                 db      33h,32h,31h,0,1,2,3,4,5,6,7,8,9,0ah,0bh,0ch,0dh,0eh,0fh
  1482.                 ; these are the 386power API & exception handlers vectors
  1483.                 align word
  1484.                 
  1485. _EXIT_OFS       dw      v16_retreal ; offset in 16bit of exit function
  1486. _EXIT_SEL       dw      20h         ; 16bit 386P code selector
  1487. _EXIT_DATA_SEL  dw      28h         ; 16bit 386P data selector
  1488.  
  1489. nextmodestack    dw      (STACKSIZE-STACKSLOT)*16 ; stack for next mode switch
  1490.  
  1491.                  align dword
  1492. tempaddr         dd      ?    ; temporary  address, seg:off or off
  1493. StackBaseAddress dd      ?    ; linear ptr to beginning of codeend
  1494.  
  1495. d32_Fast32_To_16      df      ?               ; switch from 32 to 16
  1496. d32_SaveRestoreState  df      ?               ; save/restore state addr
  1497. d32_StateBufferSize   dw      0,0             ; length of state buffer
  1498. d32_SavStackOfs       dd      ?               ; current saved stack offset
  1499. d32_SavStackSel       dw      ?               ; current saved stack selector
  1500.  
  1501. d32_OldInts           df      18 dup(?)       ; saved interrupt addr buffer
  1502.  
  1503. ;----------------------------------------------------------------------------                  
  1504. ; 32 bit VCPI system data
  1505.  
  1506. v32_vcpientryaddr df      3800000000h    ; VCPI entry point in 386P
  1507.  
  1508. ;----------------------------------------------------------------------------
  1509. ; 32 bit custom system data
  1510.  
  1511.                  align dword
  1512. s32_tssesp0ptr   dd      0               ; ptr to ESP0 in TSS, or null in VCPI
  1513. s32_idt32ptr     dd      0               ; ptr to 32bit IDT
  1514.  
  1515. s32_irq_num    dd      0               ; int num of IRQ for V86 mode
  1516. s32_SavStackOfs  dd      0               ; current saved stack offset
  1517.  
  1518. DV_INT32INTFLAG  dd      0 ; interrupt flag  for VCPI/DPMI int 32h         
  1519.                  align byte
  1520. ;---------------------------------------------------------------------------
  1521. ; 32 bit common system code
  1522. ;---------------------------------------------------------------------------
  1523.  
  1524. INIT_386P: ; common 32bit startup
  1525.  
  1526.         ; disable ctrl+break
  1527.         mov eax,gs:[1bh*4]      ; SAVE ctrl+break value, then crtl+break OFF
  1528.         mov OldBreakISR,eax     ;
  1529.         db 65h,67h,0c7h,6       ; MOV DWORD PTR GS:[1bh*4],code16:nullint
  1530.         dw 1bh*4,nullint,code16 ;
  1531.         
  1532.         in al,21h                       ; save old PIC masks
  1533.         mov ah,al                       ;
  1534.         in al,0a1h                      ;
  1535.         mov OldIRQMask,ax               ;
  1536.         
  1537.         jmp _Main                       ; go to main code
  1538.  
  1539. ; 386POWER API routines (fully compatible with PMODE API)
  1540.  
  1541. ; Allocate any mem, (first try low, then high)
  1542. ; In:
  1543. ;   EAX = size requested
  1544. ; Out:
  1545. ;   CF CLEAR = memory allocated
  1546. ;   CF SET   = not enough mem
  1547. ;   EAX = linear pointer to mem or ?
  1548. _GetMem:
  1549.         push eax
  1550.         call _GetLoMem
  1551.         jnc short getmemd
  1552.         pop eax
  1553.         jmp short _GetHiMem
  1554. getmemd:
  1555.         add esp,4
  1556.         ret
  1557.         
  1558. ; Allocate some low mem
  1559. ; In:
  1560. ;   EAX = size requested
  1561. ; Out:
  1562. ;   CF CLEAR = memory allocated
  1563. ;   CF SET   = not enough mem
  1564. ;   EAX = linear pointer to mem or ?
  1565. _GetLoMem:
  1566.         add eax,_LoMemBase
  1567.         cmp eax,_LoMemTop
  1568.         ja short getmemerr
  1569.         xchg eax,_LoMemBase
  1570.         clc
  1571.         ret
  1572. getmemerr:
  1573.         stc
  1574.         ret
  1575.         
  1576. ; Allocate some high mem
  1577. ; In:
  1578. ;   EAX = size requested
  1579. ; Out:
  1580. ;   CF CLEAR = memory allocated
  1581. ;   CF SET   = not enough mem
  1582. ;   EAX = linear pointer to mem or ?
  1583. _GetHiMem:
  1584.         add eax,_HiMemBase
  1585.         cmp eax,_HiMemTop
  1586.         ja short getmemerr
  1587.         xchg eax,_HiMemBase
  1588.         clc
  1589.         ret
  1590.         
  1591. ; Get status of IRQ mask bit
  1592. ; In:
  1593. ;   BL = IRQ num (0-15)
  1594. ; Out:
  1595. ;   AL = status: 0=enabled, 1=disabled
  1596. _GetIRQMask:
  1597.         push ax
  1598.         in al,0a1h ; get IRQ mask
  1599.         mov ah,al  ;
  1600.         in al,21h  ;
  1601.         xchg cl,bl ;
  1602.         shr ax,cl    ; shift bit to bit0
  1603.         xchg cl,bl
  1604.         and al,1     ; mask out other bits
  1605.         pop ax
  1606.         ret
  1607.         
  1608. ; Set status of IRQ mask bit
  1609. ; In:
  1610. ;   BL = IRQ num (0-15)
  1611. ;   AL = status: 0=enabled, 1=disabled
  1612. _SetIRQMask:
  1613.         push ax bx cx dx
  1614.         mov cl,bl
  1615.         mov bx,0fffeh
  1616.         movzx dx,al
  1617.         rol bx,cl
  1618.         shl dx,cl
  1619.         in al,0a1h
  1620.         mov ah,al
  1621.         in al,21h
  1622.         and ax,bx
  1623.         or ax,dx
  1624.         out 21h,al
  1625.         mov al,ah
  1626.         out 0a1h,al
  1627.         pop dx cx bx ax
  1628.         ret
  1629.         
  1630. ;------------------------------------------------------------------------------        
  1631. ; Exit to real mode
  1632.  
  1633. _Exit:  ; 32bit side of shutdown code
  1634.         cli  ; interrupts off
  1635.         ; set default timer interval into PIT0
  1636.         mov ax,36h ; PIT channel 0, square wave,binary, send LSB & MSB
  1637.         out 43h,al ; send command
  1638.         mov al,0
  1639.         out 40h,al ; maximum timer count (freq. = 18.2 Hz)
  1640.         out 40h,al ;
  1641.         mov ax,0B6h ; PIT channel 2, square wave,binary, send LSB & MSB
  1642.         out 43h,al  ; send command
  1643.         mov al,0
  1644.         out 42h,al ; maximum timer count (freq. = 18.2 Hz)
  1645.         out 42h,al ;
  1646.         sti
  1647.         mov V86ax,0003 ; restore text mode 80x25
  1648.         mov al,10h     ;
  1649.         int 33h        ;
  1650.         cli
  1651.         in al,61h           ; disable sound
  1652.         and al,011111100b   ;
  1653.         out 61h,al          ;
  1654.         mov eax,OldBreakISR              ; restore ctrl+break
  1655.         mov gs:[1bh*4],eax
  1656.         mov ax,OldIRQMask                ; restore PIC masks
  1657.         out 0a1h,al
  1658.         jc delay1  ; delay a little
  1659. delay1: jnc delay2 ;
  1660. delay2:            ;
  1661.         mov al,ah
  1662.         out 21h,al
  1663.         push _EXIT_SEL                  ; go to 16bit 386P exit code
  1664.         push _EXIT_OFS
  1665.         mov ds,_EXIT_DATA_SEL
  1666.         db 66h,0cbh             ; 16bit RETF
  1667.             
  1668. ;------------------------------------------------------------------------------
  1669. ; 32 bit DPMI system code
  1670. ;------------------------------------------------------------------------------
  1671. v32_call386P:                           ; VCPI 386P call from real mode
  1672.         mov esp,ebx ; set new stack slot
  1673.         mov ax,10h
  1674.         mov ds,ax
  1675.         mov es,ax
  1676.         mov ss,ax
  1677.         ; now share code with DPMI
  1678. d32_call386P:                           ; DPMI 386P call from real mode
  1679.         cld
  1680.         ; DS,CS,ES set by DPMI server OR by VCPI custom code
  1681.         mov ax,ds
  1682.         mov fs,ax
  1683.         mov gs,_SelZero
  1684.         ; ONLY SEGMENT REGISTERS, STACK POINTER AND Direction Flag
  1685.         ; ARE SET TO RESPECT 386Power ENVIRONMENT
  1686.         ; This is not like the Int 32h callable in protected mode !!!!
  1687.         push offset d32_call386Pdone
  1688.         push tempaddr
  1689.         cmp ds:DV_INT32INTFLAG,0
  1690.         jne d32_call_with_sti
  1691.         cli
  1692.         ret  ; now call near routine in code32
  1693. d32_call_with_sti:
  1694.         sti
  1695.         ret ; as above, but with ints enabled
  1696.                 
  1697. d32_call386Pdone:
  1698.         cli
  1699.         ; registers are trashed to gain speed on callback termination
  1700.         ; THIS IS NOT LIKE THE INT 32h IN PROTECTED MODE
  1701.         mov ecx,_Code16Base
  1702.         movzx ebx,gs:d16_SavStackOfs[ecx]
  1703.         movzx edx,gs:d16_SavStackSeg[ecx]
  1704.         mov eax,code16
  1705.         
  1706.         cmp cs:_386Man,IS_VCPI ;
  1707.         je v32_call386Pdone       ; redirect if IS_VCPI
  1708.         ; DPMI return to real mode
  1709.         mov cx,dx
  1710.         mov si,ax
  1711.         mov edi,offset DPMI_Return_Int32R
  1712.         jmp d32_Fast32_To_16
  1713.         
  1714. v32_call386Pdone:                          ; VCPI done with 386P call
  1715.         push eax
  1716.         push eax
  1717.         push eax
  1718.         push eax
  1719.         push edx
  1720.         push ebx
  1721.         pushfd
  1722.         push eax
  1723.         db 68h                      ; 32bit PUSH offset DONE_INT32R_DPMI_VCPI
  1724.         dw DONE_INT32R_DPMI_VCPI,0  ;
  1725.         mov ax,gs
  1726.         mov ds,ax
  1727.         mov ax,0de0ch
  1728.         call cs:v32_vcpientryaddr ; n.b. this is a FAR call
  1729.         
  1730. ;------------------------------------------------------------------------------        
  1731. d32_int32:                               ; DPMI INT 32h: CX:DX=seg:off
  1732.         pushad
  1733.         
  1734.         shl ecx,16  ;  store seg:ofs into ECX
  1735.         mov cx,dx   ;
  1736.         
  1737.         mov bp,offset callreal   ; redirect to CALL REAL MODE ROUTINE
  1738.         
  1739.         ; now join common int code
  1740.         jmp short d32_16common
  1741.         
  1742. d32_int33: ; DPMI INT 33h: AL=int num
  1743.         pushad
  1744.         ; AND HERE WE GO TO VIRTUAL 8086 MODE
  1745.         ; PUTTING INTO tempaddr the offset of the interrupt vector to call
  1746.         ; from the _OldInt vector table
  1747.         movzx ecx,al          ;get vector offset int _OldInt
  1748.         
  1749.         mov bp,offset intreal ; redirect to INT REAL MODE ROUTINE
  1750.         
  1751.         ; join common int code
  1752.         
  1753. d32_16common:  ; int or call to real mode
  1754.         mov ax,0900h ; DPMI get state of Interrupt Flag and DISABLE IT
  1755.         int 31h
  1756.         ; AL = Interrupt Flag status
  1757.         
  1758.         mov tempaddr,ecx ; address to jump at in seg:ofs format
  1759.         
  1760.         push ax ; save Int Flag status
  1761.         
  1762.         push d32_SavStackOfs   ; save current SAVED stack
  1763.         push d32_SavStackSel   ;
  1764.         
  1765.         movzx ebx,nextmodestack    ; allocate a new stack frame
  1766.         lea eax,[ebx-STACKSLOT*16] ;
  1767.         mov nextmodestack,ax       ;
  1768.         
  1769.         mov ax,ss ; 
  1770.         mov es,ax ; ES == save state segment
  1771.         
  1772.         sub esp,dword ptr d32_StateBufferSize ; allocate DPMI save state buffer
  1773.         mov edi,esp                           ;
  1774.         
  1775.         ; es:edi = pointer to save state buffer
  1776.         xor al,al                   ; AL=0 -> SAVE TASK STATE INFO
  1777.         call d32_SaveRestoreState   ; save DPMI info about this stack
  1778.         
  1779.         mov d32_SavStackOfs,esp  ; save stack
  1780.         mov d32_SavStackSel,ss   ;
  1781.         
  1782.         mov cx,V86es    ; real mode ES
  1783.         mov dx,codeend  ; real mode SS
  1784.         mov ax,V86ds    ; real mode DS
  1785.         
  1786.         movzx edi,bp    ; real mode EIP
  1787.         mov si,code16   ; real mode CS
  1788.         jmp d32_Fast32_To_16
  1789.         
  1790.         ; DPMI RETURN FROM V86
  1791. d32_16done:
  1792.         mov edi,esp  ; current stack pos
  1793.         ; ES:EDI == pointer to save state buffer
  1794.         mov al,1                   ; AL=1 -> RESTORE TASK STATE INFO
  1795.         call d32_SaveRestoreState  ; get last DPMI info saved 
  1796.         
  1797.         add esp,dword ptr d32_StateBufferSize ; remove DPMI INFO block
  1798.         
  1799.         pop d32_SavStackSel   ; Restore previous saved stack
  1800.         pop d32_SavStackOfs   ; 
  1801.         
  1802.         add nextmodestack,STACKSLOT*16 ; restore space used for previous 
  1803.                                        ; stack frame
  1804.         
  1805.         mov bx,V86F       ;
  1806.         mov ax,[esp+42]   ;
  1807.         and ax,not 8d5h   ;
  1808.         and bx,8d5h       ;
  1809.         or ax,bx          ;
  1810.         mov [esp+42],ax   ;  write user flags on register image on stack
  1811.         
  1812.         pop ax    ; RESTORE Int Flag found on entry to mode-switch routine
  1813.         mov ah,9  ;
  1814.         int 31h   ; restore previous Int Flag status
  1815.         
  1816.         mov ax,ds        ; restore selectors
  1817.         mov es,ax        ;
  1818.         mov fs,ax        ;
  1819.         mov gs,_SelZero  ;
  1820.         
  1821.         popad   ; restore registers
  1822.         iretd
  1823.         
  1824. ;------------------------------------------------------------------------------        
  1825. ; DPMI IRQ redirectors (needed to make all IRQ vector selectors = CS)
  1826.  
  1827. d32_irq0:
  1828.         jmp cs:d32_OldInts[0]
  1829. d32_irq1:
  1830.         jmp cs:d32_OldInts[6]
  1831. d32_irq2:
  1832.         jmp cs:d32_OldInts[12]
  1833. d32_irq3:
  1834.         jmp cs:d32_OldInts[18]
  1835. d32_irq4:
  1836.         jmp cs:d32_OldInts[24]
  1837. d32_irq5:
  1838.         jmp cs:d32_OldInts[30]
  1839. d32_irq6:
  1840.         jmp cs:d32_OldInts[36]
  1841. d32_irq7:
  1842.         jmp cs:d32_OldInts[42]
  1843. d32_irq8:
  1844.         jmp cs:d32_OldInts[48]
  1845. d32_irq9:
  1846.         jmp cs:d32_OldInts[54]
  1847. d32_irqa:
  1848.         jmp cs:d32_OldInts[60]
  1849. d32_irqb:
  1850.         jmp cs:d32_OldInts[66]
  1851. d32_irqc:
  1852.         jmp cs:d32_OldInts[72]
  1853. d32_irqd:
  1854.         jmp cs:d32_OldInts[78]
  1855. d32_irqe:
  1856.         jmp cs:d32_OldInts[84]
  1857. d32_irqf:
  1858.         jmp cs:d32_OldInts[90]
  1859.  
  1860. ;------------------------------------------------------------------------------
  1861. ; DPMI IRQ REDIRECTORS
  1862. ;------------------------------------------------------------------------------
  1863.  
  1864. ; DPMI get IRQ handler offset
  1865. ; In:
  1866. ;   BL - IRQ num (0-0fh)
  1867. ; Out:
  1868. ;   EDX - offset of IRQ handler
  1869.  
  1870. d32_getirq:
  1871.         pushad
  1872.         mov ax,0204h
  1873.         movzx bx,bl
  1874.         mov bl,intslotnum[bx]
  1875.         int 31h
  1876.         popad
  1877.         ret
  1878.         
  1879. ; DPMI set IRQ handler offset
  1880. ; In:
  1881. ;   BL - IRQ num (0-0fh)
  1882. ;   EDX - offset of IRQ handler
  1883.  
  1884. d32_setirq:
  1885.         pushad
  1886.         mov ax,0205h
  1887.         movzx bx,bl
  1888.         mov bl,intslotnum[bx]
  1889.         mov cx,cs
  1890.         int 31h
  1891.         popad
  1892.         ret
  1893.         
  1894. ;-----------------------------------------------------------------------------        
  1895. ; VCPI STUFF
  1896. ;-----------------------------------------------------------------------------
  1897.                   
  1898. ;-----------------------------------------------------------------------------
  1899. ; 32 bit custom system code
  1900. ;-----------------------------------------------------------------------------
  1901. s32_int31: ; INT 31h: AX=900h,901h,902h
  1902.         cmp al,1
  1903.         mov al,[esp+9]
  1904.         jb short s32_int31f0
  1905.         ja short s32_int31f1
  1906.         or byte ptr [esp+9],2
  1907.         jmp short s32_int31f1
  1908. s32_int31f0:
  1909.         and byte ptr [esp+9],0fdh
  1910. s32_int31f1:
  1911.         shr al,1
  1912.         and al,1
  1913.         iretd
  1914.         
  1915. ; 386POWER API ints
  1916. s32_int32:                               ; INT 32h: CX:DX=seg:off
  1917.         pushad
  1918.         shl ecx,16
  1919.         mov cx,dx
  1920.         mov ebp,offset callreal
  1921.         jmp short s32_16common
  1922.         
  1923. s32_int33:                               ; INT 33h: AL=int num
  1924.         pushad
  1925.         movzx ecx,al
  1926.         mov ebp,offset intreal
  1927.         
  1928. s32_16common: ; int or call to real mode
  1929.         mov tempaddr,ecx
  1930.         
  1931.         mov edi,[esp+40]   ; EXCTRACT FLAG INFO & PUT IT ON EDI
  1932.         shld eax,edi,23    ; 
  1933.         
  1934.         movzx esi,nextmodestack     ; new stack frame
  1935.         lea eax,[esi-STACKSLOT*16]  ;
  1936.         mov nextmodestack,ax        ; eax = new stack offset
  1937.         
  1938.         mov ebx,s32_tssesp0ptr     ;
  1939.         push dword ptr [ebx]       ; salva ESP0 relativo a data32
  1940.         
  1941.         add eax,StackBaseAddress   ; eax = new linear stack pointer data16
  1942.         mov [ebx],eax              ; STORE new stack on TSS esp0
  1943.         
  1944.         push s32_SavStackOfs       ;
  1945.         mov s32_SavStackOfs,esp    ; save stack
  1946.         
  1947.         xor eax,eax  ;
  1948.         push eax     ;
  1949.         push eax     ;  2 null dwords
  1950.         
  1951.         mov ax,V86ds  ; DS
  1952.         push eax      ;
  1953.         
  1954.         mov ax,V86es  ; ES
  1955.         push eax      ;
  1956.         
  1957.         mov ax,codeend ; SS
  1958.         push eax       ;
  1959.         
  1960.         push esi       ; ESP
  1961.         
  1962.         or edi,20000h  ;
  1963.         and di,0fdffh  ;
  1964.         push edi       ; store protected flags 
  1965.         
  1966.         db 68h                  ; 32bit PUSH code16
  1967.         dd code16               ;
  1968.         push ebp                ; epb = intreal xor callreal
  1969.         
  1970.         mov ax,0018h   ; VCPI switch to real mode routine
  1971.         mov ds,ax
  1972.         mov ax,0de0ch
  1973.         call cs:v32_vcpientryaddr  ; n.b. this is a FAR call
  1974.         
  1975. s32_int3_d:
  1976.         mov ax,18h
  1977.         mov gs,ax
  1978.         mov ax,10h
  1979.         mov ds,ax
  1980.         mov es,ax
  1981.         mov fs,ax
  1982.         mov ss,ax
  1983.         mov esp,s32_SavStackOfs
  1984.         pop s32_SavStackOfs
  1985.         mov ebx,s32_tssesp0ptr
  1986.         pop dword ptr [ebx]
  1987.         mov bx,V86F
  1988.         
  1989. ;-----------------------------------------------------------------------------
  1990. s32_int3_d2:                             ; done with INT32/33 from real or V86
  1991.         add nextmodestack,STACKSLOT*16
  1992.         mov ax,[esp+40]
  1993.         and ax,not 8d5h
  1994.         and bx,8d5h
  1995.         or ax,bx
  1996.         mov [esp+40],ax
  1997.         popad
  1998.         iretd
  1999.         
  2000. ;------------------------------------------------------------------------        
  2001. ; exceptions handlers: some are terminal, others are redirected
  2002. ; to the irq handler.
  2003.  
  2004.         ; exceptions 0..7 are reflected to the real mode interrupts 0..7
  2005. s32_exc0:
  2006.         mov byte ptr ss:s32_irq_num,0
  2007.         jmp s32_irq
  2008. s32_exc1:
  2009.         mov byte ptr ss:s32_irq_num,1
  2010.         jmp s32_irq
  2011. s32_exc2:
  2012.         mov byte ptr ss:s32_irq_num,2
  2013.         jmp s32_irq
  2014. s32_exc3:
  2015.         mov byte ptr ss:s32_irq_num,3
  2016.         jmp s32_irq
  2017. s32_exc4:
  2018.         mov byte ptr ss:s32_irq_num,4
  2019.         jmp s32_irq
  2020. s32_exc5:
  2021.         mov byte ptr ss:s32_irq_num,5
  2022.         jmp s32_irq
  2023. s32_exc6:
  2024.         mov byte ptr ss:s32_irq_num,6
  2025.         jmp short s32_exc
  2026. s32_exc7:
  2027.         mov byte ptr ss:s32_irq_num,7
  2028.         jmp s32_irq
  2029.         
  2030.         ; exceptions 8..0Fh produces program termination
  2031.         ; maybe in a future release i will support 
  2032.         ; a core dumper for post mortem debug
  2033. s32_exc8:
  2034.         pushad
  2035.         mov al,8
  2036.         jmp short s32_exc
  2037. s32_exc9:
  2038.         pushad
  2039.         mov al,9
  2040.         jmp short s32_exc
  2041. s32_exca:
  2042.         pushad
  2043.         mov al,0ah
  2044.         jmp short s32_exc
  2045. s32_excb:
  2046.         pushad
  2047.         mov al,0bh
  2048.         jmp short s32_exc
  2049. s32_excc:
  2050.         pushad
  2051.         mov al,0ch
  2052.         jmp short s32_exc
  2053. s32_excd: ; general protection violation
  2054.         pushad
  2055.         mov al,0dh
  2056.         jmp s32_exc        
  2057. s32_exce:
  2058.         pushad
  2059.         mov al,0dh
  2060.         jmp short s32_exc
  2061. s32_excf:
  2062.         pushad
  2063.         mov al,0FFh  ; GENERIC failure
  2064. ;-----------------------------------------------------------------------------
  2065. s32_exc: ; main exception handler
  2066.         ; on entry al=error code (not used)
  2067.         
  2068.         mov ax,10h        ; set up descriptors for termination
  2069.         mov ds,ax         ;
  2070.         mov es,ax         ;
  2071.         mov fs,ax         ;
  2072.         mov gs,_SelZero   ;
  2073.     cld
  2074.         jmp _Exit         ; TERMINATE PROGRAM
  2075.         
  2076. ; IRQ redirector between modes
  2077.  
  2078. s32_irq0:
  2079.         mov byte ptr ss:s32_irq_num,8
  2080.         jmp s32_irq
  2081. s32_irq1:
  2082.         mov byte ptr ss:s32_irq_num,9
  2083.         jmp s32_irq
  2084. s32_irq2:
  2085.         mov byte ptr ss:s32_irq_num,0ah
  2086.         jmp s32_irq
  2087. s32_irq3:
  2088.         mov byte ptr ss:s32_irq_num,0bh
  2089.         jmp short s32_irq
  2090. s32_irq4:
  2091.         mov byte ptr ss:s32_irq_num,0ch
  2092.         jmp short s32_irq
  2093. s32_irq5:
  2094.         mov byte ptr ss:s32_irq_num,0dh
  2095.         jmp short s32_irq
  2096. s32_irq6:
  2097.         mov byte ptr ss:s32_irq_num,0eh
  2098.         jmp short s32_irq
  2099. s32_irq7:
  2100.         mov byte ptr ss:s32_irq_num,0fh
  2101.         jmp short s32_irq
  2102. s32_irq8:
  2103.         mov byte ptr ss:s32_irq_num,70h
  2104.         jmp short s32_irq
  2105. s32_irq9:
  2106.         mov byte ptr ss:s32_irq_num,71h
  2107.         jmp short s32_irq
  2108. s32_irqa:
  2109.         mov byte ptr ss:s32_irq_num,72h
  2110.         jmp short s32_irq
  2111. s32_irqb:
  2112.         mov byte ptr ss:s32_irq_num,73h
  2113.         jmp short s32_irq
  2114. s32_irqc:
  2115.         mov byte ptr ss:s32_irq_num,74h
  2116.         jmp short s32_irq
  2117. s32_irqd:
  2118.         mov byte ptr ss:s32_irq_num,75h
  2119.         jmp short s32_irq
  2120. s32_irqe:
  2121.         mov byte ptr ss:s32_irq_num,76h
  2122.         jmp short s32_irq
  2123. s32_irqf:
  2124.         mov byte ptr ss:s32_irq_num,77h
  2125. ;-----------------------------------------------------------------------------
  2126. ; generic IRQ handler, al =INT to call if V86 routine has to be called
  2127. ;
  2128. s32_irq: ; select IRQ type: real->v86 or p->v86
  2129.          ; this is a real mode IRQ happened while in protected mode
  2130.         push ds 
  2131.         push es 
  2132.         push fs 
  2133.         push gs     
  2134.         
  2135.         pushfd
  2136.         push cs
  2137.         push offset s32_irqpd
  2138.         pushad
  2139.         mov ax,ss
  2140.         mov ds,ax
  2141.         mov gs,_SelZero
  2142.         mov ecx,s32_irq_num
  2143.         mov ebp,offset s16_irqreal
  2144.         jmp s32_16common
  2145. s32_irqpd:
  2146.         pop gs 
  2147.         pop fs 
  2148.         pop es 
  2149.         pop ds
  2150.         iretd
  2151.  
  2152. ; Custom get IRQ handler offset
  2153. ; In:
  2154. ;   BL - IRQ num (0-0fh)
  2155. ; Out:
  2156. ;   EDX - offset of current IRQ handler
  2157. s32_getirq:
  2158.         push ebx
  2159.         pushf
  2160.         cli
  2161.         movzx ebx,bl             ;
  2162.         mov bl,intslotnum[ebx]   ;
  2163.         lea ebx,[ebx*8]          ;  get location in IDT table
  2164.         add ebx,s32_idt32ptr
  2165.         mov dx,[ebx+6]          ;
  2166.         shl edx,16              ;  read ISR offset from IDT
  2167.         mov dx,[ebx]            ;
  2168.         popf
  2169.         pop ebx
  2170.         ret
  2171.         
  2172. ; Custom set IRQ handler offset
  2173. ; In:
  2174. ;   BL  - IRQ num (0-0fh)
  2175. ;   EDX - offset of new IRQ handler
  2176. s32_setirq:
  2177.         pushad
  2178.         pushf
  2179.         cli
  2180.         movzx ebx,bl            ;
  2181.         mov bl,[ebx+intslotnum] ;
  2182.         lea ebx,[ebx*8]         ; get location in IDT table
  2183.         add ebx,s32_idt32ptr    ;
  2184.         mov [ebx],dx            ; modify descriptor for 
  2185.         shr edx,16              ; new 32bit offset & same segment
  2186.         mov [ebx+6],dx          ;
  2187.         popf
  2188.         popad
  2189.         ret
  2190.  
  2191. code32  ends
  2192.  
  2193. ; End of program 
  2194. ; (codeend segment must be at end of program or you will get lots of pain)
  2195.  
  2196. codeend segment para stack use32 'stack'
  2197. db      STACKSIZE*16 dup(?)
  2198.         ; Stack Starts here
  2199. codeend ends
  2200.         end     Boot16
  2201.  
  2202.